/**
 * java多线程模式
 * @author andy.rong
 */
package com.myjavalab.thread;

import java.util.Random;

public class ProducerCustomerPattern {

	public static void main(String[] args) {
		Table table = new Table(3);
		MakerThread m1 = new MakerThread("Maker1", table, 32837);
		MakerThread m2 = new MakerThread("Maker2", table, 34837);
		MakerThread m3 = new MakerThread("Maker3", table, 32537);
		EaterThread e1 = new EaterThread("Eater1", table, 31237);
		EaterThread e2 = new EaterThread("Eater2", table, 42837);
		EaterThread e3 = new EaterThread("Eater3", table, 52837);
		ClearThread c0 = new ClearThread("Cleaner0", table);
		
		m1.start();
		m2.start();
		m3.start();
		e1.start();
		e2.start();
		e3.start();
		c0.start();
		
		try{
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		m1.interrupt();
		e1.interrupt();
		c0.interrupt();
	}
}

class MakerThread extends Thread{
	private final Random random;
	private final Table table;
	private static int id = 0;
	
	public MakerThread(String name, Table table, int seeds) {
		super(name);
		this.table = table;
		this.random = new Random(seeds);
	}
	
	public void run() {
		try {
			while(true) {
				Thread.sleep(random.nextInt(1000));
				String cake = "[Cake No." + nextId() + "] by " + getName();
				table.put(cake);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	private static synchronized int nextId() {
		return id++;
	}
}

class EaterThread extends Thread {
	private final Random random;
	private final Table table;
	
	public EaterThread(String name, Table table, int seeds) {
		super(name);
		this.table = table;
		this.random = new Random(seeds);
	}

	public void run() {
		try {
			while(true) {
				table.take();
				Thread.sleep(random.nextInt(1000));
				
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
}

class ClearThread extends Thread {

	private final Table table;
	public ClearThread(String name, Table table) {
		super(name);
		this.table = table;
	}
	
	public void run() {
		try{			
			while(true) {
				Thread.sleep(1000);
				System.out.println("========= " + getName() + " clears ===========");
				table.clear();
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

class Table{

	private final String[] buffer;
	private int tail;
	private int head;
	private int count;
	
	public Table(int size) {
		this.buffer = new String[size];
		this.head = 0;
		this.tail = 0;
		this.count = 0;
	}
	
	public synchronized void put(String cake) throws InterruptedException {
		while(count >= buffer.length) {
			wait();
		}
		buffer[tail] = cake;
		tail = (tail + 1) % buffer.length;
		count++;
		System.out.println(Thread.currentThread().getName() + " puts " + cake);
		notifyAll();
	}
	
//	public String take() throws InterruptedException {
	public synchronized String take() throws InterruptedException {
		while(count <= 0) {
			System.out.println("      " + Thread.currentThread().getName() + " is waiting");
			Thread.sleep(1000);
			wait();
		}
		String cake = buffer[head];
		head = (head + 1) % buffer.length;
		count--;
		notifyAll();
		System.out.println("      " + Thread.currentThread().getName() + " takes " + cake);
		return cake;
	}
		
	public synchronized void clear() {
		count = 0;
		head = 0;
		tail = 0;
		notifyAll();
	}
}